package by.grsu.hdm;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

import by.grsu.hdm.devices.Receiver;
import by.grsu.hdm.devices.RemoteControl;
import by.grsu.hdm.devices.MediaCenter;
import by.grsu.hdm.devices.NetworkMonitor;
import by.grsu.hdm.devices.UsbFlashDrive;
import by.grsu.hdm.devices.WashingMachine;
import by.grsu.hdm.exception.EmptyFileSystemException;
import by.grsu.hdm.exception.ProgramAlreadyLoadedException;
import by.grsu.hdm.model.IDevice;
import by.grsu.hdm.model.IFileSystem;
import by.grsu.hdm.model.IHomeDevice;
import by.grsu.hdm.model.INetworkAvailable;
import by.grsu.hdm.model.IUsbPort;
import by.grsu.hdm.model.IUsbSupport;
import by.grsu.hdm.reporting.TextReportBuilder;
import by.grsu.hdm.reporting.TrafficReportData;
import by.grsu.hdm.software.MediaPlayer;

public class HomeDeviceManagerStarter {
	static final Logger logger = Logger.getLogger(HomeDeviceManagerStarter.class.getName());
	
	private static final String WASHING_MACHINE_ID = "WASHING#45";
	private static final String RECEIVER_ID = "Receiver#03h";
	private static final String MEDIA_PLAYER_PID = "MP#001";
	private static final String USB_FLASH_DRIVE_NAME = "FLASH-4GB";
	private static final String MEDIA_CENTER_ID = "MEDIA#132456";
	
	static {
		BasicConfigurator.configure();
	}

	public static void main(String[] args) {
		List<IHomeDevice> devices = new ArrayList<IHomeDevice>();
		
		MediaCenter media = new MediaCenter(MEDIA_CENTER_ID);
		media.getUsbPort().connectDevice(new UsbFlashDrive(USB_FLASH_DRIVE_NAME));
		
		// loading MediaPlayer program in MediaCenter
		try {
			logger.info(media.loadProgram(new MediaPlayer(MEDIA_PLAYER_PID)).getMessage());
		} catch (ProgramAlreadyLoadedException e) {
			e.printStackTrace();
		}
		
		Receiver receiver = new Receiver(RECEIVER_ID, ((MediaPlayer) media.getProgram()));
		
		devices.add(media);
		devices.add(new WashingMachine(WASHING_MACHINE_ID));
		devices.add(receiver);
		
		// turn all devices on
		turnOnDevices(devices);
		
		// check for connected devices
		checkingConnectedDevices(devices);
		
		// check for connected device with filesystem and making it the source for mediaplayer
		mediaPlayerSetSource(devices, media);
			
		// TEST: demonstration of playlist's repeat playing and MediaPlayer status messages
		mediaPlayerTestPlayback(media);
		
		// adding remote control to control MediaPlayer
		RemoteControl remoteControl = remoteControlAdding(receiver);
		
		remoteControlTest(media, remoteControl);
		
		// register devices for network monitoring
		NetworkMonitor monitor = networkMonitorRegisterDevices(devices);

		printNetworkMonitorReport(monitor);
		
		// unloading mediaplayer program from mediacenter's memory
		logger.info(media.closeProgram().getMessage());

		// turn all devices off
		turnOffDevices(devices);
	}

	private static void turnOffDevices(List<IHomeDevice> devices) {
		for (IHomeDevice device : devices) {
			device.turnOff();
		}
	}

	private static void turnOnDevices(List<IHomeDevice> devices) {
		for (IHomeDevice device : devices) {
			device.turnOn();
		}
	}

	private static void remoteControlTest(MediaCenter media,
			RemoteControl remoteControl) {
		remoteControl.playNext();
		logger.info(((MediaPlayer)media.getProgram()).getMediaPlayerStatus().getMessage());
		remoteControl.playNext();
		logger.info(((MediaPlayer)media.getProgram()).getMediaPlayerStatus().getMessage());
	}

	private static RemoteControl remoteControlAdding(Receiver receiver) {
		RemoteControl remoteControl = new RemoteControl();
		remoteControl.addRCSignalAvailableEventListener(receiver);
		return remoteControl;
	}

	private static void printNetworkMonitorReport(NetworkMonitor monitor) {
		TrafficReportData reportData = monitor.getNetworkStatistics();
		TextReportBuilder text = new TextReportBuilder(reportData);
		String report = text.buildReport();
		logger.info(report);
	}

	private static NetworkMonitor networkMonitorRegisterDevices(
			List<IHomeDevice> devices) {
		NetworkMonitor monitor = new NetworkMonitor();
		for (IDevice device : devices) {
			if (device instanceof INetworkAvailable) {
				monitor.registerDevice((INetworkAvailable)device);
			}
		}
		return monitor;
	}

	private static void mediaPlayerTestPlayback(MediaCenter media) {
		if (media.getProgram() instanceof MediaPlayer) {
			MediaPlayer mediaPlayer = ((MediaPlayer)media.getProgram());
			
			mediaPlayer.play();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
			mediaPlayer.playNext();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
			mediaPlayer.play();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
			mediaPlayer.playNext();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
			mediaPlayer.playNext();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
			mediaPlayer.playNext();
			logger.info(mediaPlayer.getMediaPlayerStatus().getMessage());
		}
	}

	private static void checkingConnectedDevices(List<IHomeDevice> devices) {
		for (IDevice device : devices) {
			if (device instanceof IUsbSupport) {
				IUsbPort usb = ((IUsbSupport)device).getUsbPort();
				if (usb.hasConnectedDevice()) {
					IDevice usbDevice = usb.getConnectedDevice();
					if (usbDevice != null)
						logger.info(usbDevice.getDeviceId() + " is connected to " + device.getDeviceId());
				}
			}
		}
	}
	
	private static void mediaPlayerSetSource(List<IHomeDevice> devices,
			MediaCenter media) {
		if (media.getProgram() instanceof MediaPlayer) {
			MediaPlayer mediaPlayer = ((MediaPlayer)media.getProgram());
			
			for (IDevice device : devices) {
				if (device instanceof IUsbSupport) {
					IUsbPort usb = ((IUsbSupport)device).getUsbPort();
					if (usb.hasConnectedDevice()) {
						IDevice usbDevice = usb.getConnectedDevice();
						if ((usbDevice != null) && (usbDevice instanceof IFileSystem)) {
							try {
								mediaPlayer.setSource((IFileSystem)usbDevice);
							} catch (EmptyFileSystemException e) {
								e.printStackTrace();
							}
						}
					}
				}
			}
		}
	}
}